Fix ToChatResponse to use first appropriate CreatedAt instead of last#7193
Merged
stephentoub merged 7 commits intomainfrom Jan 5, 2026
Merged
Fix ToChatResponse to use first appropriate CreatedAt instead of last#7193stephentoub merged 7 commits intomainfrom
stephentoub merged 7 commits intomainfrom
Conversation
…f last Changed the logic in ProcessUpdate to prefer the first valid CreatedAt value (non-null and after Unix epoch) rather than the latest one. This fixes the issue where UsageContent updates with later timestamps were incorrectly overwriting the message CreatedAt with a value that doesn't reflect when the actual message content was generated. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix inaccurate CreatedAt returned by ToChatResponse
Fix ToChatResponse to use first appropriate CreatedAt instead of last
Jan 5, 2026
stephentoub
reviewed
Jan 5, 2026
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs
Show resolved
Hide resolved
…ixEpoch under #if NET - Updated comments in ProcessUpdate to clarify that CreatedAt prefers first valid value - Used DateTimeOffset.UnixEpoch under #if NET instead of custom _unixEpoch field Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where ToChatResponse{Async} was incorrectly using the timestamp from the last update rather than the first update when constructing a ChatResponse. This caused inaccurate CreatedAt values when usage updates arrive significantly after content updates (e.g., in the Mistral API where usage updates can be delayed by several minutes).
Key Changes:
- Modified timestamp handling to use "first valid value wins" behavior instead of "last value wins"
- Added
IsValidCreatedAthelper that treats values ≤ Unix epoch (1970-01-01) as null/invalid - Updated all affected tests to reflect the new first-wins behavior and use valid timestamps (years ≥ 1970)
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs |
Changed ProcessUpdate to set CreatedAt only when null (first-wins), added IsValidCreatedAt helper and Unix epoch constant |
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/ChatCompletion/ChatResponseUpdateExtensionsTests.cs |
Updated test timestamps from invalid years (1, 2) to valid ones (2024, 2025), updated expected values to match first-wins behavior, and corrected comments to reflect new semantics |
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs
Show resolved
Hide resolved
stephentoub
reviewed
Jan 5, 2026
src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatResponseExtensions.cs
Outdated
Show resolved
Hide resolved
stephentoub
reviewed
Jan 5, 2026
...crosoft.Extensions.AI.Abstractions.Tests/ChatCompletion/ChatResponseUpdateExtensionsTests.cs
Show resolved
Hide resolved
stephentoub
approved these changes
Jan 5, 2026
Simplified the IsValidCreatedAt helper to use direct comparison (createdAt > UnixEpoch) instead of pattern matching first. The comparison returns false when the nullable value is null. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Added test cases to validate that datetime values less than Unix epoch (not just equal to it) are treated the same as null: - Added test cases to ToChatResponse_TimestampFolding_MemberData for 1969 and 1960 dates - Updated ToChatResponse_AlternativeTimestamps to include a before-epoch timestamp Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
This was referenced Feb 4, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ToChatResponse{Async}should use the first update's CreatedAt instead of the lastChatResponseExtensions.cslines 521-524 (message) and 566-569 (response)DateTimeOffset.UnixEpochunder#if NETinstead of custom fieldIsValidCreatedAtto use direct nullable comparisonSummary
Changed the
ToChatResponse{Async}implementation so that theCreatedAtproperty reflects the first appropriate update'sCreatedAtproperty rather than the last. Values that are less than or equal to the Unix epoch are treated as null (invalid). This ensures that when streaming responses from providers like Mistral, theCreatedAtaccurately reflects when the message content was generated, not when the usage update was received.Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
Microsoft Reviewers: Open in CodeFlow